home *** CD-ROM | disk | FTP | other *** search
Text File | 1990-07-16 | 38.9 KB | 1,120 lines |
-
-
-
- ┌────────────────────────────┐
- │VMM - Virtual Memory Manager│
- └────────────────────────────┘
-
- A complementary unit for Object Professional
- a package from TurboPower Software
-
- Author : Patrick Philippot - 7/90
-
-
- ╔═══════════════════════════════════════════════════╗
- ║This package is released to the public domain. It║
- ║can be distributed to anyone FOR FREE. I DO NOT║
- ║authorize anyone to charge ANY AMOUNT of money║
- ║for this package wathever the media used to║
- ║distribute it. ║
- ╚═══════════════════════════════════════════════════╝
-
- First of all let me apologize for my rather poor
- english. I hope anyone will understand the
- following documentation.
-
- WARNING : You need Turbo Professional version 1.0x
- to compile this package.
-
- *****************
-
-
-
- A. Overview
-
- The Virtual Memory Manager object (VMM) allows you to allocate memory for
- dynamic variables without being limited by the size of the Turbo Pascal
- heap. That is, VMM is not a replacement system for the Turbo Pascal memory
- manager but it provides you with an easy-to-use complementary package able
- to temporarily store allocated blocks in EMS or on disk and to automatically
- move them into RAM when they are needed.
-
- VMM was written with the following specifications in mind:
-
- - VMM methods do not replace the System.GetMem and System.FreeMem routines.
- They can peacefully coexist with VMM without any trouble. VMM memory blocks
- are allocated in a separate RAM area, allocated on the heap. This area does
- not interfere with the memory areas managed by Turbo Pascal itself.
-
- - The VMM object is intended to be a complementary memory management
- system which will be used to allocate medium sized blocks of memory (or
- numerous smaller ones) that don't need to be present in RAM at any time.
-
- - VMM does not require the Turbo Pascal compiler to be patched to generate
- a particular interrupt each time a pointer is dereferenced. Instead, it
- provides a dereferencing routine which is to be applied to each pointer
- returned by VMM. This will guarantee compatibility with future versions of
- Turbo Pascal.
-
- - VMM is an object. This provides you with the general advantages related
- to objects but also with this one : you can generate as many objects of type
- VMM as you want, each of them dealing with different kind of data. This is
- very much like having several heaps enabled to use disk and EMS to swap out
- data, each of them being dedicated to a particular role in your application.
-
- Using VMM
-
- All the internal mechanisms of VMM are fully transparent to you and adding
- the capabilities of VMM to your applications is very straightforward.
-
- First of all, like for many objects, you have to initialize the VMM
- object. This is done using one of two methods. The Init method initializes
- the VMM with default options which are suitable for most cases. You only
- have to provide the name of the swap file. The InitCustom method allows you
- to gain more control over the VMM object and to specify the initialization
- parameters.
-
- Then you will allocate memory blocks using the GetMemV method and free them
- using the FreeMemV method. Dereferencing is made thru the VmmDrf inline
- macro. Dereferencing a pointer means that you make reference to the data it
- points to by adding a caret (^) after the name of the pointer.
-
- When your program terminates or if you want to recover the space used in RAM,
- EMS and on disk by your VMM, you'll call the Done method.
-
- That's all.
-
- VMMTEST1 and VMMTEST2 are short programs showing you the whole process of
- initializing a VMM, allocating and freeing memory with it. Since they allocate
- a lot of virtual memory blocks they execute rather lengthy. They were used to
- debug the VMMNGR unit.
-
-
- B. Dynamic arrays
-
- Although Dynamic Arrays are not specific to the VMM, we use them heavily
- in the VMM design. This allows VMM to use the smallest possible amount
- of RAM memory to store the structures needed to manage the allocated blocks.
- Dynamic Arrays can be used for many other purposes so we decided to include
- the related documentation in this section.
-
- The DynArray object allows you to create arrays holding elements of any size,
- growing dynamically when a size increase is needed. DynArrays are very
- useful when the number of elements in the array is not known at compile time
- and when other dynamic structures like linked lists or queues are not
- relevant.
-
- A DynArray is not as easy to use as a "normal" array because elements cannot
- be accessed directly. However this drawback is compensated by the fact that
- DynArrays are more generic and can hold elements of any type.
-
- The total size of a dynamic array as well as the size of a single element
- cannot exceed 64k. More accurately, 65521 bytes.
-
- Although this capability is not used by VMM objects, DynArrays can be
- stored to and loaded from streams.
-
- EXDYNARR.PAS shows you how DynArrays work.
-
- --------------------------------------------------------------------------------
- Init
-
- Declaration
- constructor Init(MaxElements, ElementSize, Incr : Word);
-
- Purpose
- Initializes an empty DynArray.
-
- Description
- Sets data area pointer to nil, item count to zero and initializes other data
- from the passed parameters. MaxElements is the maximum number of items the
- dynamic array may contain. ElementSize is the size of a single item. Incr is
- the basis used to calculate the minimum size increment when inserting new
- items. Since inserting a new item may cause the data area to be reallocated,
- choosing a very small value for Incr will naturally save memory space but
- will cause heap fragmentation. For example, giving Incr the value of 128
- will cause space for 128 items to be allocated even if only the first item
- has been inserted. Inserting the 129th item will cause space for 128
- additional items to be allocated.
-
- No space is allocated for the array until an element is inserted.
-
- Example
- MyDynArray.Init(100, SizeOf(LongInt), 5);
- Initializes a dynamic array containing at most 100 elements of type LongInt.
- The size of the array will be increased by increments of 5*4 bytes.
-
- --------------------------------------------------------------------------------
- Done
-
- Declaration
- destructor Done; virtual;
-
- Purpose
- Destroy a DynArray.
-
- Description
- Frees data area and resets data area pointer to nil.
-
- Example
- MyDynArray.Done;
-
- See Also
- Clear
-
- --------------------------------------------------------------------------------
- SetElem
-
- Declaration
- procedure SetElem(Index : Word; var Elem);
-
- Purpose
- Move the contents of Elem in the indexth element of the DynArray.
-
- Description
-
- Valid indexes range from 0 to MaxElements minus 1. DynArrays are always 0
- based. Allocates enough space to the data area to hold at least Index
- elements. Elements which have not been set are filled with nulls. If Index
- is not a valid index, GetStatus returns epFatal+ecBadParam. If there is not
- enough memory available to allocate to the data area, GetStatus returns
- epFatal+ecOutOfMemory.
-
- Index may range from 0 to GetMaxIndex.
-
- Example
- var
- L : LongInt;
-
- L := 100000;
- MyDynArray.SetElem(50, L);
-
- Puts the value 100000 in the 51th element of MyDynArray.
-
- See Also
- GetElem GetValidElems GetMaxIndex
-
- --------------------------------------------------------------------------------
- GetElem
-
- Declaration
- procedure GetElem(Index : Word; var Elem);
-
- Purpose
- Puts the value of the Indexth element of array in Elem.
-
- Description
-
- Provided Index is a valid index, Elem will be loaded with the value
- contained in the Indexth element of the array. It is assumed that Elem is big
- enough to hold one element of the array. Otherwise memory will be overwritten.
-
- Example
- var
- L : LongInt;
-
- MyDynArray.GetELem(20, L);
- if L = TestValue then
- ...
- Puts value of 21th element of the array in L.
-
- See Also
- GetValidElems SetElem GetMaxIndex
-
- --------------------------------------------------------------------------------
- GetElemSize
-
- Declaration
- function GetElemSize : Word;
-
- Purpose
- Return size of a single element.
-
- Description
- Returns size passed to the ElemSize parameter in the Init method.
-
- Example
- if MyDynArray.GetElemSize > 4 then
- ...
- Tests if size of one element is greater than 4 bytes.
-
- See Also
- Init
-
- --------------------------------------------------------------------------------
- GetArraySize
-
- Declaration
- function GetArraySize : Word;
-
- Purpose
- Return the actual size in bytes allocated to the data area.
-
- Description
-
- As the elements are inserted the size of the dynamically allocated data area
- increases. GetArraySize return the size occupied by the data area on the
- heap independently from the number of elements actually used.
-
- Example
- var
- L : LongInt;
- S : Word;
- MyDynArray.Init(100, SizeOf(LongInt), 20);
- L := 100000
- SetElem(0, L);
- S := MyDynArray.GetArraySize;
- {S now yields 20*4 bytes}
- L := 200000
- SetElem(1, L);
- S := MyDynArray.GetArraySize;
- {S still yields 80 bytes}
-
- See Also
- GetValidElems
-
- --------------------------------------------------------------------------------
- GetMaxIndex
-
- Declaration
- function GetMaxIndex : Word;
-
- Purpose
- Return maximum admissible value for an index regardless of the actual size
- of the data area.
-
- Description
- This is the greatest value acceptable for the Index parameter passed to the
- Init method. It is equal to MaxElements-1.
-
- Example
- MyDynArray.Init(100, SizeOf(LongInt), 20);
- I := MyDynArray.GetMaxIndex;
- {I now yields 99}
-
- --------------------------------------------------------------------------------
- GetValidElems
-
- Declaration
- function GetValidElems : Word;
-
- Purpose
- Return the maximum index that can be passed as a parameter to GetElem.
-
- Description
- Although the Init method specifies the greatest number of elements a dynamic
- array may contain, no memory is allocated to hold all these elements unless
- a call to SetElem is made for the latest element in the array. The actual
- size of the data area is not a good information because we allocate memory
- for it with minimum increments. So the GetElem method should not use indexes
- greater than GetValidElems-1.
-
- Example
- var
- L : LongInt;
- I : Word;
- MyDynArray.Init(100, SizeOf(LongInt), 20);
- I := MyDynArray.GetMaxIndex;
- {I = 99}
- L := 100000
- SetElem(0, L);
- I := MyDynArray.GetValidElems;
- {I = 1}
- L := 200000
- SetElem(9, L);
- S := MyDynArray.GetValidElems;
- {I = 10}
-
- See Also
- GetMaxIndex
-
- --------------------------------------------------------------------------------
- Shrink
-
- Declaration
- procedure Shrink(ElemNb : Word);
-
- Purpose
- Decrease data area size and discard exceeding elements.
-
- Description
- Reallocate the data area and discard elements above index ElemNb-1. If
- ElemNb is greater than GetValidElems nothing happens. This doesn't prevent
- from setting any element between the first (index 0) and the last elements
- (GetMaxIndex).
-
- Example
- MyDynArray.Shrink(50);
-
- --------------------------------------------------------------------------------
- Clear
-
- Declaration
- procedure Clear;
-
- Purpose
- Reset the dynamic array and discard any data.
-
- Description
- Disposes of the data area and reset all internal variables. The dynamic array
- is left in the same state as after the Init method has been run.
-
- Example
- MyDynArray.Clear;
-
- --------------------------------------------------------------------------------
- Load
-
- Declaration
- constructor Load(var S : IdStream);
-
- Purpose
- Load the dynamic array from a stream.
-
- Description
- S is a properly intialized stream object.
-
- Load reads the next sequence of bytes from the stream S. These bytes must
- have been written by a previous call to DynARray.Store. Load allocates heap
- space for the data area, copy the data to that area and initializes all
- internal variables. The dynamic array is left in the same state as it was
- when the call to the Store method was made.
-
- if Load fails, the constructor will return False and the error code will
- be stored in the global variable InitStatus.
-
- The stream registration procedure for a DynArray is DynArrayStream.
-
- Example
- MyDynArray.Load(S);
-
- See Also
- Store
-
- --------------------------------------------------------------------------------
- Store
-
- Declaration
- constructor Store(var S : IdStream);
-
- Purpose
- Store the dynamic array to a stream.
-
- Description
- S is a properly intialized stream object.
-
- Store writes an image of the DynArray to the stream S. The image includes
- the array data, the current number of valid elements, the maximum number of
- elements, the size of the data area, the minimum grow increment, the maximum
- number of elements and the size of a single element.
-
- To check for errors that have occured during the Store, call the stream's
- GetStatus function.
-
- The stream registration procedure for a DynArray is DynArrayStream.
-
- Example
- MyDynArray.Store(S);
-
- See Also
- Load
- --------------------------------------------------------------------------------
- GetStatus
-
- Declaration
- function GetStatus : Word;
-
- Purpose
- Return status code and reset internal result to zero.
-
- Description
- Each DynArray maintains an internal variable that stores the current status of
- the dynamic array. GetStatus provides direct access to this variable. Like
- IOResult, GetStatus clears the internal status variable after it returns the
- current value.
-
- When no error has occured GetStatus returns 0. Otherwise it returns an error
- code as specified in the Error handling section. Expected error values
- include:
-
- epFatal+ecBadParam
- epFatal+ecOutOfMemory
-
- Example
- MyDynArray.SetElem(10, V);
- if GetStatus <> 0 then begin
- {process error}
- ...
- end;
-
- --------------------------------------------------------------------------------
- PeekStatus
-
- Declaration
- function PeekStatus : Word;
-
- Purpose
- Return status and leave internal variable unchanged.
-
- Description
- Works like GetStatus but doesn't clear the internal status variable.
-
- --------------------------------------------------------------------------------
- Error
-
- Declaration
- procedure Error(Code : Word);
-
- Purpose
- Report an error.
-
- Description
- Applications do not call this routine directly. When a DynArray method
- detects an error, it calls the error method to report it. The default
- implementation of this method simply assigns the error code to an internal
- status variable. An object derived from VMM may override the Error method
- to provide different error handling behavior.
-
- --------------------------------------------------------------------------------
-
- C. The Virtual Memory Manager
-
- Although VMM is very simple to use, it's important to have a look at the
- way it works. You will use VMMs more efficiently if you have some ideas
- about the GPVMM design.
-
- VMM components are:
-
- - the VMM pointers which are actually handles returned by the GetMemV
- procedure. These pointers have to be considered like normal pointers by the
- user except that they cannot be dereferenced directly. The VmmDrf inline
- macro has to be used to dereference such pointers.
-
- - the RAM area which is used as a transfer area where memory blocks are
- first allocated and to which or from which these blocks are paged in and out
- if needed. When you allocate a block with the GetMemV procedure you can be
- sure that the block is present in the RAM area just after calling GetMemV.
- (in general you cannot assume that a particular block is present in memory).
- Later, if we need room in the RAM area to allocate a new block or to page in
- an older one, blocks present in the RAM area will be paged out using the LRU
- algorithm until enough memory space has been made free. The RAM area is
- allocated on the Turbo Pascal heap. It may be greater than 64k, provided you
- replace the standard GetMem procedure by a routine of your own. A hook is
- provided for that.
-
- - the Freelists, which are used to keep track of free blocks in RAM, EMS and
- on disk. Freelists are all derived from the DynArray object type which has
- been described in the previous section. There are 3 freelists :
- vmRamFreeList, vmEmsFreeList and vmDskFreeList.
-
- - the Descriptor Table, which is able to translate a VMM pointer returned
- by GetMemV into a record holding all the information about the memory block.
- A VMM Descriptor knows where a block is located, whether it is locked in
- RAM and where it is located on the actual media containing it (RAM, EMS or
- swap file). The Descriptor is also derived from the DynArray type.
-
- - The LRU queue which keeps track of the Least Recently Used VMM pointers
- (handles). When paging out is needed, VMM first swaps out the blocks that
- were used (which pointers were dereferenced) least recently. This is
- achieved by pushing a VMM pointer (actually, only the handle part of it)
- into the LRU queue each time it created or dereferenced. If the VMM
- pointer already exists in the queue it is removed before adding it to the
- queue. The LRU queue is derived from the OPROOT StaticQueue object. It has
- two additional methods : IsEmpty which returns true if the queue is empty
- and Remove which is able to remove the fist occurence of an element in a
- StaticQueue updating data and head and tail pointers. VMM always try to
- remove a handle from the LRU queue before adding to the tail. This makes sure
- that the handle will be unique in the queue. Trying to page out the same
- handle twice would cause a system error.
-
- - The dereference handler. This procedure (actually an interrupt handler) is
- not part of the object definition. Its name is DerefHandler and it is called
- by the VmmDrf inline macro. The interrupt vector used is 66h.
-
- Interrupt 66h is one of the user-definable interrupts described by IBM. If
- this interrupt conflicts with your environment, you may change the global
- typed constant VmIntUsed to use a different interrupt. User-definable
- interrupts range from 60h to 66h. (67h is used for EMS, so it should be
- avoided here). If you change the interrupt, be sure to modify the VmmDrf
- inline function as well.
-
- The interrupt vector is restored when your program exits or when a runtime
- error occurs.
-
- Since the dereference handler does not know which VMM has generated the
- pointer which is to be dereferenced, it refers to a global pointer called
- VmmActiveMgr. This pointer is set by a special method, LinkToDerefHandler,
- which stores the value of the SELF pointer into VmmActiveMgr. This way, the
- dereference handler always knows which data to use. Failing to call
- LinkToDerefHandler before dereferencing a VMM pointer will likely cause
- your program to hang.
-
- If you used GetMemV to allocate space for a dynamic record, you'll need to do
- some typecasting to access the different fields of the record. Example:
-
- type
- MyRec = record
- I : Integer;
- W : Word;
- S : String;
- end;
- MyRecPtr = ^MyRec;
-
- var
- MyPtr = MyRecPtr;
-
- ...
- GetMemV(MyPtr, SizeOf(MyRec));
- ...
- VmmDrf(MyPtr)^.S {Will generate a compiler error}
- MyRecPtr(VmmDrf(MyPtr))^.S {Will compile}
- MyRec(VmmDrf(MyPtr)^).S {Will compile}
-
-
- When you request a memory allocation, the following process occurs.
-
- First, the VMM object examines the RAM area to check if enough memory is
- available. If not, memory blocks will be paged out to EMS or disk until enough
- memory is available in the RAM area. Blocks are paged out to EMS first and
- then to disk. The VMM will not use all EMS or disk space available. You can
- control this by setting the EmsToKeep and DskToKeep parameters when calling
- InitCustom. The defaults used by the Init method are 1 megabyte disk space
- and 10% of the available Ems memory left free.
-
- When memory blocks are dereferenced, the same mechanism occurs until the
- block can be loaded into the RAM area. Under some circumstances it may be
- possible that all virtual memory ressources (EMS and disk) are exhausted and
- that not enough free space is available in the RAM area. In order to prevent
- such a "dead lock", VMM refuses to allocate space if there is not enough
- space in EMS or on disk to page out 3 times the size of the RAM area. Keeping
- free only as many bytes as the RAM area can hold is not sufficient because of
- fragmentation and because we may have for example to swap out to disk blocks
- that have been primarily paged in from EMS.
-
- VMM allows the RAM area to be greater than 64k. Though, since this area is
- allocated on the Turbo Pascal heap, it is not possible to use System.GetMem to
- achieve this. If you have replacement routines for System.GetMem and
- System.FreeMem, you can tell VMM to use them by setting the value of two
- global procedure variables : UserGetMem and UserFreeMem. These routines must
- be of type GetMemFUnc and FreeMemProc:
-
- GetMemFunc = function(var P; Size : LongInt) : Boolean;
- FreeMemProc = procedure(var P; Size : LongInt);
-
- UserGetMem must return nil if no allocation was made.
- UserFreeMem must set the pointer to nil.
-
- UserGetMem defaults to VmmGetMem and UserFreeMem defaults to VmmFreeMem which
- are revised versions of GetMemCheck and FreeMemCheck found in OpRoot.
-
- VMM has very few options. You can only specify if you VMM to use only
- EMS virtual memory or only disk virtual memory. Disabling both ressources
- wouldn't make much sense. So it's impossible. Another option let you specify
- if the swap file has to be deleted when the VMM object is destroyed. This
- is the default option. Keeping the swap file on the disk will be sometimes
- useful for debugging purposes.
-
- Both vmUseEms and vmUseDsk options are set to true unless the corresponding
- parameter of InitCustom explicitly excludes one of these ressources (empty
- name for the swap file or NoEms -$FFFF- constant for EmsToKeep). Lack of
- both ressources when a VMM is initialized causes the initialization
- process to fail. If either EMS or disk space are not present in sufficient
- amounts, the corresponding option is set to false. If your program later
- releases some EMS memory or delete some files you may try to activate the
- relevant option.
-
- --------------------------------------------------------------------------------
- Init
-
- Declaration
- constructor Init(SwapFName : PathStr);
-
- Purpose
- Initialize a Virtual Memory Manager.
-
- Description
- Init initializes the VMM using default options. You only have to provide
- the name of the swap file. Init calls InitCustom with the following
- parameters:
-
- MaxHeapAlloc = 65521 bytes
- DefIncr = 128 bytes
- DefFreeEntries div 2 = 1024 entries / 4096 bytes
- DefFreeEntries = 2048 entries / 8192 bytes
- DefQueueSize = 1024-1 entries
- DefEmsToKeep = 10% of Ems pages available when Init is called
- DefDskToKeep = 1 megabyte is left free on swap disk
-
- Please refer to the description of InitCustom to have an explanation of the
- meaning of these parameters. Using Init will be sufficient in most cases.
-
- Don't worry about the way you pass the swap filename. This name will be
- expanded (via FExpand) to produce a full qualified unique filename.
-
- Example
- VM.Init('VMM.SWP');
- VM.LinkToDerefHandler;
-
- See Also
- InitCustom LinkToDerefHandler
-
- --------------------------------------------------------------------------------
- InitCustom
-
- Declaration
- constructor InitCustom(RamSize : LongInt;
- Incr, MaxVmmEntries,
- MaxFreeEntries, VmmQueueEntries,
- EmsPagesToKeep : Word;
- DskToKeep : LongInt;
- SwapFName : PathStr);
-
- Purpose
- Initialize a Virtual Memory Manager with custom options.
-
- Description
- InitCustom provides a more sophisticated way of initializing a VMM.
-
- RamSize specifies how much memory has to be allocated on the Turbo Pascal
- heap for the RAM area. This size may be greater than 64k, provided
- UserGetMem (see above) points to a routine allowing such a huge allocation.
- Init uses a default of 65521 bytes.
-
- Incr is the increment used to initialize the dynamic arrays holding the
- freelists. Please refer to the DynArray.Init method to understand the role
- of this increment value.
-
- MaxVmmEntries specifies the maximum number of VMM pointers that can be
- allocated by the memory manager. This doesn't mean that space is reserved
- for all of these entries. Space is allocated on demand when entries are
- created by GetMemV.
-
- MaxFreeEntries defines the maximum number of entries in the freelists.
- Freelists do not need to be very big unless you generate a big number of
- VMM pointers or you use FreeMemV very heavily. The default values of Init
- will do in almost all circumstances.
-
- VmmQueueEntries specifies how many handles can be held in the LRU queue.
- Because the RAM area is much smaller than the memory space available in EMS
- or on disk, you don't need to set up a very big LRU queue. In theory, to be
- sure that the paging process will never fail we should have as many entries
- in the LRU queue as we can hold memory blocks in the RAM area. A very
- extreme case would be allocating blocks of one byte. Assuming we would have
- a RAM area of 65521 bytes, we would need 65521 entries in LRU queue! This is
- impossible because each entry need two bytes. Most of the time a VMM will
- deal with middle sized memory blocks. So using a default of 512 entries will
- be sufficient.
-
- EmsPagesToKeep specifies how many EMS pages the VMM should leave free at
- any time for the application program (or for another VMM). If you want to
- use, say, 2 VMM in an application and you don't want to see the EMS
- resource to be exhausted by the first VMM, leaving only disk virtual
- memory for the second one, you can set the EmsToKeep parameter to a higher
- value for the first initialized VMM than for the second one.
-
- If EmsToKeep equals NoEms ($FFFF) the vmUseEms option is deactivated. This
- way the virtual memory manager will use only disk to page out memory blocks.
-
- DskToKeep specifies how much disk space the VMM should leave free at any
- time for the application program (or for another VMM). The same remark as
- for the EMS memory applies here too.
-
- SwapFName is the name of the swap file. If this name is an empty string, the
- vmUseDsk option is deactivated.
-
- Example
- VM.InitCustom(30000, 50, 500, 500, 150, 50, 0, '');
- VM.LinkToDerefHandler;
-
- Initializes VM with a RAM area of 30000 bytes, a minimum increment of 50
- entries for the dynamic arrays, a maximum number of 500 entries in the
- Descriptor Table (that is 500 VMM pointers) and in the freelists. 50 EMS
- pages will be left free and the disk will not be used for paging out.
-
- See Also
- Init LinkToDerefHandler
-
- --------------------------------------------------------------------------------
- Done
-
- Declaration
- destructor Done; virtual;
-
- Purpose
- Destroy a virtual memory manager.
-
- Description
- All dynamic arrays used by the VMM are destroyed and the memory they used
- is released to the heap. The RAM area memory is also released to the heap.
- All EMS handles allocated by the VMM are deallocated. The swap file is
- closed and deleted (unless the vmDeleteSwap option is off).
-
- Example
- VM.Done;
-
- --------------------------------------------------------------------------------
- GetMemV
-
- Declaration
- procedure GetMemV(var Pt; BlkSize : Word);
-
- Purpose
- Allocate a memory block in RAM area and return a VMM pointer in Pt.
-
- Description
- GetMemV first searches for a free block of size BlkSize in the RAM area. If
- it doesn't find such a block it pages out memory blocks present in the RAM
- area (beginning with the Less Recently Used) until sufficient memory space
- has been made free to allocate the new block. If this process fails, it
- returns a nil pointer. Otherwise it returns a VMM pointer in Pt. This
- pointer is not a real pointer. The offset part is always $FFFF and the
- segment part is a handle which will be used to enter the Descriptor Table
- where information about the allocated block is stored.
-
- The returned pointer cannot be used like a normal pointer. It must be
- "dereferenced" thru the VmmDrf function.
-
- The new handle is added to the tail of the LRU queue.
-
- Example
- var
- P : ^string;
- ...
- VM.GetMemV(P, Length(str)+1);
- VmmDrf(P)^ := str;
-
- Allocates enough space to hold str.
-
- See Also
- FreeMemV VmmDrf
-
- --------------------------------------------------------------------------------
- FreeMemV
-
- Declaration
- procedure FreeMemV(var Pt);
-
- Purpose
- Release memory used by Pt.
-
- Description
- The memory block used by Pt is deallocated. The corresponding entry in the
- Descriptotr Table is marked as a free entry. A new entry is inserted in the
- relevant freelist. Pt is set to nil.
-
- You don't need to specify the size of the block because the Descriptor Table
- keeps track of this. This is necessary to manage the freelists and much more
- convenient for you.
-
- Example
- VM.FreeMemV(P);
-
- See Also
- GetMemV
-
- --------------------------------------------------------------------------------
- LinkToDerefHandler
-
- Declaration
- procedure LinkToDerefHandler;
-
- Purpose
- Make the DerefHandler aware of which VMM is active.
-
- Description
- Since the dereference handler is called by an INT instruction, we cannot
- specify to which VMM it has to refer. Only one VMM can be active at a
- given time. It is the last one which issued a call to LinkToDerefHandler.
- This one line procedure stores the value of the SELF pointer into a global
- variable which will be referred to by the dereference handler.
-
- Using VMM.VmmDrf without linking the VMM to the dereference handler is
- very much like using unitialized pointers. This will likely cause a program
- failure.
-
- Example
- VM.LinkToDerefHandler;
-
- See Also
- VmmDrf
-
- --------------------------------------------------------------------------------
- Lock
-
- Declaration
- function Lock(var Pt; Lockit : Boolean) : Boolean;
-
- Purpose
- Prevent a memory block from being paged out.
- Allow a block to be paged out.
-
- Description
-
- Lock updates the Descriptor Table entry corresponding to the passed VMM
- pointer (Pt) and sets the "lock" bit if Lockit is true. The handle is
- removed from the LRU queue. From now on, the block cannot be paged out any
- more. It will remain in the RAM area. The block is unlocked by passing a
- value of False in Lockit.
-
- Lock will be used to make sure that a block remains in memory even when
- another pointer is dereferenced. Lock works even if the block pointed to by
- Pt is presently not in RAM. If you dereference the corresponding pointer,
- the block will be moved to the RAM area and will stay there until you unlock
- it.
-
- Lock should be use with extreme care because locking one or several blocks
- in the RAM area may cause the paging out process to fail if the dereferenced
- pointer points to a block which is too big to fit into the remaining space.
- You should make sure that the locked block(s) and the blocks that will be
- paged into the RAM area have a total size smaller than the RAM area size. A
- block should be locked in RAM for very short periods of time and unlocked as
- soon as its presence in RAM is no more necessary.
-
- To help you managing this you may want to use the ClearRamArea method before
- locking blocks.
-
- As we said a VMM is a complementary memory management system that should be
- used only for temporarily storing medium sized data out of the heap not for
- storing blocks that are used very often.
-
- Example
- if VM.Lock(MyPtr, true) then
- ...
-
- See Also
- ClearRamArea
-
- --------------------------------------------------------------------------------
- GetSize
-
- Declaration
- function GetSize(var Pt) : Word;
-
- Purpose
- Return the size of the memory block pointed to by Pt.
-
- Description
- GetSize looks into the Descriptor Table and returns the size stored in the
- corresponding descriptor.
-
- Example
- S := VM.GetSize(MyPtr);
-
- --------------------------------------------------------------------------------
- ClearRamArea
-
- Declaration
- function ClearRamArea : Boolean;
-
- Purpose
- Page out all non locked memory blocks.
-
- Description
- ClearRamArea is a simple call to the internal method called PageOut,
- requesting the system to page out all blocks stored in the RAM area unless
- they are locked. After a call to ClearRamArea, if there is no locked blocks
- you can be sure that the entire RAM area is free of any data. If you want to
- make sure that 2 or 3 blocks can be present in RAM simultaneaously, use
- ClearRamArea before dereferencing the corresponding pointers. ClearRamArea
- returns true if all the RAM area has been cleared.
-
- Example
- if not VM.ClearRamArea then
- Writeln('Some blocks are still locked in RAM.');
-
- See Also
- Lock
-
- --------------------------------------------------------------------------------
- RamMaxAvail
-
- Declaration
- function RamMaxAvail : LongInt;
-
- Purpose
- Return the size of the biggest free memory block in the RAM area.
-
- Description
- RamMaxAvail return the size of the last entry in the RamFreeList. Since all
- freelists are always sorted in size order, the size of the last entry is the
- size of the biggest free block.
-
- Example
- S := VM.RamMaxAvail;
-
- --------------------------------------------------------------------------------
- EmsMaxAvail
-
- Declaration
- function EmsMaxAvail : LongInt;
-
- Purpose
- Return the size of the biggest free memory block in Ems.
-
- Description
- EmsMaxAvail return the size of the last entry in the EmsFreeList or 64k if
- sufficient EMS is available to allocate a 4 pages frame. Since all freelists
- are always sorted in size order, the size of the last entry is the size of
- the biggest free block.
-
- Example
- S := VM.EmsMaxAvail;
-
- --------------------------------------------------------------------------------
- DskMaxAvail
-
- Declaration
- function DskMaxAvail : LongInt;
-
- Purpose
- Return the size of the biggest free memory block on disk.
-
- Description
- DskMaxAvail return the size of the last entry in the DskFreeList or the
- amount of disk space available minus DskToKeep. Since all freelists are
- always sorted in size order, the size of the last entry is the size of the
- biggest free block.
-
- Example
- S := VM.DskMaxAvail;
-
- --------------------------------------------------------------------------------
- vmOptionsOn
-
- Declaration
- procedure vmOptionsOn(OptionFlags : Word);
-
- Purpose
- Turn specified VMM options on.
-
- Description
-
- Turning vmUseDsk or vmUseEms options has no effect if there is not enough disk
- or EMS space available.
-
- Example
- VM.vmOptionsOn(vmUseDsk)
-
- --------------------------------------------------------------------------------
- vmOptionsOff
-
- Declaration
- procedure vmOptionsOff(OptionFlags : Word);
-
- Purpose
- Turn specified VMM options off.
-
- Description
- Setting both vmUseDsk and vmUseEms options off is not possible. Doing so
- would cause VMM to work in RAM only, that is with very limited resources.
- For example, if you already set vmUseEms off and try to do the same with
- vmUseDsk, it will remain on.
-
- Example
- VM.vmOptionsOff(vmDeleteSwap)
-
- --------------------------------------------------------------------------------
- vmOptionsAreOn
-
- Declaration
- function vmOptionsAreOn(OptionFlags : Word) : Boolean;
-
- Purpose
- Return TRUE if OptionCodes are enabled.
-
- Description
- This routine allows to determine whether a single option or multiple options
- are on. The possible options for VMM are vmUseDsk, vmUseEms, vmDeleteSwap.
-
- Example
- if VM.vmOptionsAreOn(vmUseEms) then
- {VM is using Ems...}
-
- --------------------------------------------------------------------------------
- GetStatus
-
- Declaration
- function GetStatus : Word;
-
- Purpose
- Return status code and reset internal result to zero.
-
- Description
- Each VMM maintains an internal variable that stores the current status of
- the memory manager. GetStatus provides direct access to this variable. Like
- IOResult, GetStatus clears the internal status variable after it returns the
- current value.
-
- When no error has occured GetStatus returns 0. Otherwise it returns an error
- code as specified in the Error handling section. Expected error values
- include:
-
- epNonFatal+ecOutOfRamEntries
- epNonFatal+ecOutOfEmsEntries
- epNonFatal+ecOutOfDskEntries
- epNonFatal+ecCantFreeEms
- epFatal+ecOutOfDescEntries
- epFatal+ecBadParam
- epFatal+ecEmsAllocation
- epFatal+ecEmsPageMapping
- epFatal+any I/O error
-
- Example
- if not VM.ClearRamArea then
- Error := GetStatus;
- {process error}
- ...
- end;
-
- --------------------------------------------------------------------------------
- PeekStatus
-
- Declaration
- function PeekStatus : Word;
-
- Purpose
- Return status and leave internal variable unchanged.
-
- Description
- Works like GetStatus but doesn't clear the internal status variable.
-
- --------------------------------------------------------------------------------
- Error
-
- Declaration
- procedure Error(Code : Word);
-
- Purpose
- Report an error.
-
- Description
- Applications do not call this routine directly. When a VMM method detects an
- error, it calls the error method to report it. The default implementation of
- this method simply assigns the error code to an internal status variable. An
- object derived from VMM may override the Error method to provide different
- error handling behavior.
-
-
- D. Error handling
-
- Beside the GetStatus and PeekStatus functions a VMM can generate runtime
- errors. In some cases a program cannot recover from an error. If a bad
- pointer is passed to VmmDrf or if dereferencing is not possible because the
- EMS manager failed or because there are too much locked blocks in memory,
- the only way out is a runtime error. This very much like runtime errors
- occuring when the System.GetMem or System.FreeMem procedures fail.
-
- Runtime errors generated by VMM are:
-
- 211 : Abstract method not overridden (should not occur).
- 212 : Non recoverable EMS error.
- 213 : Could not page out or bad pointer.
- 204 : Invalid pointer operation.
- epFatal+I/O error : non recoverable disk error (only when dereferencing)
-
- Before halting the program the VMM unit restores INT 66h. Another
- mechanism which is not processed by the Exit procedure, deallocates all EMS
- handles allocated by all VMMs before calling the RunError procedure.
-
- <Patrick Philippot - 16/7/90>